package cz.acies.uniql.sql.functions;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.dom.DOMElement;


import cz.acies.uniql.dialect.Dialect;
import cz.acies.uniql.sql.UniQLExpr;
import cz.acies.uniql.sql.element.UniQLColumn;
import cz.acies.uniql.sql.element.UniQLCondition;
import cz.acies.uniql.sql.element.UniQLCriterion;
import cz.acies.uniql.sql.element.UniQLValue;
import cz.acies.utils.StringUtils;

@Deprecated
public class SQLAritFunc extends SQLFunc
{
	private static final long serialVersionUID = -6101420557116053078L;
	
	private static final int PLUS 	= 0; 	// "+"
	private static final int MINUS 	= 1; 	// "-"
	private static final int MULTI 	= 2; 	// "*"
	private static final int DIV 	= 3; 	// "/"
	
	private static LinkedHashMap<String, Integer> operators = new LinkedHashMap<String, Integer>();
	static {
		operators.put("+", new Integer(PLUS));
		operators.put("-", new Integer(MINUS));
		operators.put("*", new Integer(MULTI));
		operators.put("/", new Integer(DIV));
	}
	private static List<String> opidx = new ArrayList<String>(operators.keySet());
	
	private int op = -1;	
	private UniQLExpr expr1, expr2;
	
	/**
	 * Kontruktuor tridy SQLAritFunc 
	 */	
	public SQLAritFunc() {
	}

	/**
	 * Konstruktor tridy SQLAritFunc
	 * 
	 * @param dialect Objekt type Dialect
	 */	
	public SQLAritFunc(Dialect dialect) {
		super(dialect);
	}

	/**
	 * Instantiates a new SQL arimt func.
	 * 
	 * @param expr1 je objekt typu String new UniQLExpr
	 * @param operator je objekt typu String jeho� hodnotou je matamatick� oper�tor (tj. "+","-","*","/")
	 * @param expr2 je parametr typu String new UniQLExpr
	 */
	public SQLAritFunc(Object expr1, String operator, Object expr2) {
		super();
		try {
			setOperator(operator);
			setLeftFragment(expr1);		
			setRightFragment(expr2);
		} catch (Exception exc) {
			exc.printStackTrace();
		}
	}

	// -----  -----------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.element.UniQLExpr#translate()
	 */	
	public String translate() throws Exception {
		Dialect dialect = this.getDialect();
		StringBuffer sb = new StringBuffer("(");
		if (this.parameters != null && !this.parameters.isEmpty()) {
			for (int i = 0; i < this.parameters.size(); i++) {
				Object obj = this.parameters.get(i);
				if (obj instanceof String) {
					if (i < this.parameters.size()-1) {
						sb.append(" "+obj+" ");
					}
				} else if (obj instanceof UniQLExpr) {
					UniQLExpr expr = (UniQLExpr)obj;
					expr.setUniQLProperties(this);
					sb.append(expr.translate());
				}
			} 
		} else if (getLeftFragment() != null) {
			getLeftFragment().setDialect(dialect);
			sb.append(getLeftFragment().translate()+" ");
			if (getOperatorString() != null) {
				sb.append(getOperatorString().trim()+" ");
				if (getRightFragment() != null) {
					getRightFragment().setDialect(dialect);
					sb.append(getRightFragment().translate()+" ");
				} else 
					return "";
			} else 
				return "";
		} else {
			return "";
		}
		sb.append(")");
		return sb.toString();
	}
	
	// -----  -----------------------------------------------------------------

	private ArrayList<Object> parameters;
	
	public SQLFunc addParam (String expr) {
		UniQLColumn column = new UniQLColumn(expr);
		this.addParam (column, "");
		return this;
	}
	
	public SQLFunc addParam (UniQLExpr expr) {
		this.addParam (expr, "");
		return this;
	}

	public SQLAritFunc addParam (String expr, String op) {
		UniQLColumn column = new UniQLColumn(expr);
		this.addParam (column, op);
		return this;
	}
	
	public SQLAritFunc addParam (UniQLExpr expr, String op) {
		if (this.parameters == null) this.parameters = new ArrayList<Object>();
		if (expr != null) this.parameters.add(expr);
		if (op != null) this.parameters.add(op);
		return this;
	}
	
	public SQLAritFunc addParam (UniQLExpr expr, String op, UniQLExpr expr2) throws Exception {
		setLeftFragment(expr);
		setOperator(op);
		setRightFragment(expr2);
		return this;
	}
	
	// -----  -----------------------------------------------------------------
	
	/**
	 * Nastavi priv�tn� prom�nnou expr1.
	 * 
	 * @param expr je objekt typu String new UniQLExpr
	 */
	public void setLeftFragment(Object expr) throws Exception { 
		if (expr instanceof String) {
			String s = ((String)expr).trim();
			if (StringUtils.isDigit((String)expr) || s.startsWith("'")) {
				//UniQLValue value = new UniQLValue(s);
				//value.set(s);
				//this.expr2 = value;
				this.expr2 = new UniQLValue(s);
			} else 
				this.expr1 = new UniQLColumn((String)expr);
		} else if (expr instanceof UniQLExpr) {
			this.expr1 = (UniQLExpr)expr;
		}
	}

	public UniQLExpr getLeftFragment() {
		return this.expr1;
	}

	/**/

	/**
	 * Nastavi priv�tn� prom�nnou expr2.
	 * 
	 * @param expr je objekt typu String nebo UniQLExpr
	 */	
	public void setRightFragment(Object expr) throws Exception { 
		if (expr instanceof String) {
			String s = ((String)expr).trim();
			if (StringUtils.isDigit(s) || s.startsWith("'")) {
				UniQLValue value = new UniQLValue();
				value.set(s);
				this.expr2 = value; 
			} else 
				this.expr2 = new UniQLColumn((String)expr);
		} else if (expr instanceof UniQLExpr) {
			this.expr2 = (UniQLExpr)expr;
		}
	}
	
	public UniQLExpr getRightFragment() {
		return this.expr2;
	}
	
	// -----  -----------------------------------------------------------------

	public void setOperator(int op) {
		this.op = op;
	}

	public void setOperator(String key) {
		if (operators.containsKey(key.trim())) this.op = ((Integer)operators.get(key)).intValue();
	}

	public int getOperator() {
		return this.op;
	}

	public String getOperatorString() {
		String s = new String();
		if (op >= 0 && op <= 3) {
			s = opidx.get(this.op);
		}
		return s;
	}
	
	// -----  -----------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.functions.SQLFunc#transToXML()
	 */
	public String transToXML() throws Exception {
		DOMElement node = new DOMElement("SQLAritFunc");
		transToXML(node);
		return node.asXML();
	}
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.functions.SQLFunc#transToXML(org.dom4j.dom.DOMElement)
	 */
	public DOMElement transToXML(DOMElement node) throws Exception {
		node.setName("SQLAritFunc");
		node.setAttribute("name", this.getName());
		if (this.parameters != null && !this.parameters.isEmpty()) {
			Element params = new DOMElement("params");
			int count = this.parameters.size();
			for (int i = 0; i < count; i++) {
				Object obj = this.parameters.get(i);
				if (obj instanceof String) {
					Element child = new DOMElement("operator");
					child.addAttribute("name", ""+obj);
					params.add(child);
				} if (obj instanceof UniQLExpr) {
					try {
						String xml = ((UniQLExpr)obj).transToXML();
						Document doc = DocumentHelper.parseText(xml);
						Element root = doc.getRootElement();
						params.add(root);							
					} catch (Exception exc) {
						exc.printStackTrace();
					}
				}
			}
			node.add(params);
		} else {
			if (expr1 != null) {
				try {
					String xml = expr1.transToXML();
					Document doc = DocumentHelper.parseText(xml);
					Element root = doc.getRootElement();
					node.add(root);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			node.addAttribute("operator", getOperatorString());
			if (expr2 != null) {
				try {
					String xml = expr2.transToXML();
					Document doc = DocumentHelper.parseText(xml);
					Element root = doc.getRootElement();
					node.add(root);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return node;
	}
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.functions.SQLFunc#xmlToExpr(java.lang.String)
	 */
	public UniQLExpr xmlToExpr(String xml) throws Exception {
		Document doc = DocumentHelper.parseText(xml);
		return xmlToExpr(doc.getRootElement());
	}

	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.functions.SQLFunc#xmlToExpr(org.dom4j.Element)
	 */
	@Override
	@SuppressWarnings("unchecked")	
	public UniQLExpr xmlToExpr(Element node) throws Exception {
		String operator = node.attributeValue("operator");
		this.setOperator(operator);
		ArrayList<Element> params = new ArrayList<Element>(node.elements());
		if (params != null && !params.isEmpty()) {
			if (params.size() == 2) {
				int i = 0;
				for (Iterator<Element> iterator = params.iterator(); iterator.hasNext();) {
					Element param = (Element) iterator.next();
					UniQLExpr expr = paramNodeToExpr(param);
					switch (i) {
						case 0: { setLeftFragment(expr);	break; }
						case 1: { setRightFragment(expr);	break; }
					}
					i++;
				}
			} else {
				for (int i = 0; i < params.size(); i++) {
					Element param = (Element)params.get(i);
					//String nodename = param.getName();
					UniQLExpr expr = paramNodeToExpr(param);
					if (expr != null) {
						this.addParam(expr);
					}
				}	
			}
		}
		return this;
	}
	
	private UniQLExpr paramNodeToExpr(Element param) throws Exception {
		String nodename = param.getName();
		UniQLExpr expr = null;
		if (nodename.trim().equals("UniQLColumn")) {
			expr = new UniQLColumn(getDialect()).xmlToExpr(param);
		} else if (nodename.trim().equals("UniQLValue")) {
			expr = new UniQLValue(getDialect()).xmlToExpr(param);
		} else if (nodename.trim().equals("UniQLCriterion")) {
			expr = new UniQLCriterion(getDialect()).xmlToExpr(param);	
		} else if (nodename.trim().equals("UniQLCondition")) {
			expr = new UniQLCondition(getDialect()).xmlToExpr(param);
		} else if (nodename.trim().equals("SQLAritFunc")) {
			expr = new SQLAritFunc(getDialect()).xmlToExpr(param);
		} else if (nodename.trim().equals("SQLAritFunc2")) {
			expr = new SQLAritFunc2(getDialect()).xmlToExpr(param);
		} else if (nodename.trim().equals("SQLAgregFunc")) {
			expr = new SQLFunc(getDialect()).xmlToExpr(param);
		} else if (nodename.trim().equals("SQLFunc")) {	
			expr = new SQLAgregFunc(getDialect()).xmlToExpr(param);
		}		
		return expr; 
	}
	
	//---------------------------------

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		/*
		String s = this + " [" + this.getLeftFragment() + ", " + 
			this.getOperatorString() + ", " + 
			this.getRightFragment() + 
		"]";
		*/
		return "SQLAritFunc" + " [" + this.getLeftFragment() + ", " + 
			this.getOperatorString() + ", " + 
			this.getRightFragment() + 
		"]";
		//return ""+this.getName()+" ("+this.getParameters() +")";
	}

}
